
#include "MultiSelectComboBox.h"
#include <QLineEdit>
#include <QCheckBox>
#include <QEvent>

namespace {
    const int scSearchBarIndex = 0;
}

/*
 * 函数名：MultiSelectComboBox
 * 函数说明:构造函数
 *
 *
 * 输入参数：parent： 父类指针
 * 输出参数：无
 * 返回值：无
 * */
MultiSelectComboBox::MultiSelectComboBox(QWidget* aParent) :
    QComboBox(aParent),
    mListWidget(new QListWidget(this)),
    mLineEdit(new QLineEdit(this)),
    mSearchBar(new QLineEdit(this))
{
    QListWidgetItem* curItem = new QListWidgetItem(mListWidget);
    mSearchBar->setPlaceholderText("Search..");
    mSearchBar->setClearButtonEnabled(true);
    mListWidget->addItem(curItem);
    mListWidget->setItemWidget(curItem, mSearchBar);

    mLineEdit->setReadOnly(true);
    mLineEdit->installEventFilter(this);

    setModel(mListWidget->model());
    setView(mListWidget);
    setLineEdit(mLineEdit);

    connect(mSearchBar, &QLineEdit::textChanged, this, &MultiSelectComboBox::onSearch);
    connect(this, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &MultiSelectComboBox::itemClicked);
}

/*
 * 函数名：hidePopup
 * 函数说明:重写隐藏popup 不再选中一个item后popup收起
 *
 *
 * 输入参数：无
 * 输出参数：无
 * 返回值：无
 * */
void MultiSelectComboBox::hidePopup()
{
    int width = this->width();
    int height = mListWidget->height();
    int x = QCursor::pos().x() - mapToGlobal(geometry().topLeft()).x() + geometry().x();
    int y = QCursor::pos().y() - mapToGlobal(geometry().topLeft()).y() + geometry().y();
    if (x >= 0 && x <= width && y >= this->height() && y <= height + this->height())
    {
        // Item was clicked, do not hide popup
    }
    else
    {
        QComboBox::hidePopup();
    }
}


/*
 * 函数名：stateChanged
 * 函数说明:通知mLineEdit选中的条目有变化，显示的信息需要修改
 *
 *
 * 输入参数：aState
 * 输出参数：无
 * 返回值：无
 * */
void MultiSelectComboBox::stateChanged(int aState)
{
    Q_UNUSED(aState);
    QString selectedData("");
    int count = mListWidget->count();

    for (int i = 1; i < count; ++i)
    {
        QWidget *widget = mListWidget->itemWidget(mListWidget->item(i));
        QCheckBox *checkBox = static_cast<QCheckBox *>(widget);

        if (checkBox->isChecked())
        {
            selectedData.append(checkBox->text()).append(";");
        }
    }
    if (selectedData.endsWith(";"))
    {
        selectedData.remove(selectedData.count() - 1, 1);
    }
    if (!selectedData.isEmpty())
    {
        mLineEdit->setText(selectedData);
    }
    else
    {
        mLineEdit->clear();
    }

    mLineEdit->setToolTip(selectedData);
    emit selectionChanged(selectedData);
}


/*
 * 函数名：addItem
 * 函数说明:添加item
 *
 *
 * 输入参数：aText：item文本
 * 输出参数：无
 * 返回值：无
 * */
void MultiSelectComboBox::addItem(const QString& aText, const QVariant& aUserData)
{
    Q_UNUSED(aUserData);
    QListWidgetItem* listWidgetItem = new QListWidgetItem(mListWidget);
    QCheckBox* checkBox = new QCheckBox(this);
    checkBox->setText(aText);
    mListWidget->addItem(listWidgetItem);
    mListWidget->setItemWidget(listWidgetItem, checkBox);
    connect(checkBox, &QCheckBox::stateChanged, this, &MultiSelectComboBox::stateChanged);
}


/*
 * 函数名：currentText
 * 函数说明:返回当前选中的list
 *
 *
 * 输入参数：无
 * 输出参数：无
 * 返回值：QStringList：选中的list
 * */
QStringList MultiSelectComboBox::currentText()
{
    QStringList emptyStringList;
    if(!mLineEdit->text().isEmpty())
    {
        emptyStringList = mLineEdit->text().split(';');
    }
    return emptyStringList;
}


/*
 * 函数名：addItems
 * 函数说明:添加多个item
 *
 *
 * 输入参数：aTexts：item文本列表
 * 输出参数：无
 * 返回值：无
 * */
void MultiSelectComboBox::addItems(const QStringList& aTexts)
{
    foreach(const QString& string , aTexts)
    {
        addItem(string);
    }
}


/*
 * 函数名：count
 * 函数说明:原生的count函数返回目前的popup中有多少条item，因为有searchbar，那一条应该不算
 *
 *
 * 输入参数：无
 * 输出参数：无
 * 返回值：无
 * */
int MultiSelectComboBox::count() const
{
    int count = mListWidget->count() - 1;// Do not count the search bar
    if(count < 0)
    {
        count = 0;
    }
    return count;
}


/*
 * 函数名：onSearch
 * 函数说明:查找操作
 *
 *
 * 输入参数：无
 * 输出参数：无
 * 返回值：无
 * */
void MultiSelectComboBox::onSearch(const QString& aSearchString)
{
    for(int i = 1; i < mListWidget->count(); i++)
    {
        QCheckBox* checkBox = static_cast<QCheckBox*>(mListWidget->itemWidget(mListWidget->item(i)));
        if(checkBox->text().contains(aSearchString, Qt::CaseInsensitive))
        {
            mListWidget->item(i)->setHidden(false);
        }
        else
        {
            mListWidget->item(i)->setHidden(true);
        }
    }
}

/*
 * 函数名：itemClicked
 * 函数说明:item点击事件
 *
 *
 * 输入参数：aIndex：点击索引
 * 输出参数：无
 * 返回值：无
 * */
void MultiSelectComboBox::itemClicked(int aIndex)
{
    if(aIndex != scSearchBarIndex)// 0 means the search bar
    {
        QWidget* widget = mListWidget->itemWidget(mListWidget->item(aIndex));
        QCheckBox *checkBox = static_cast<QCheckBox *>(widget);
        checkBox->setChecked(!checkBox->isChecked());
    }
}


/*
 * 函数名：SetSearchBarPlaceHolderText
 * 函数说明:设置占位符
 *
 *
 * 输入参数：aPlaceHolderText：占位符文本
 * 输出参数：无
 * 返回值：无
 * */
void MultiSelectComboBox::SetSearchBarPlaceHolderText(const QString& aPlaceHolderText)
{
    mSearchBar->setPlaceholderText(aPlaceHolderText);
}


/*
 * 函数名：SetPlaceHolderText
 * 函数说明:设置占位符
 *
 *
 * 输入参数：aPlaceHolderText：占位符文本
 * 输出参数：无
 * 返回值：无
 * */
void MultiSelectComboBox::SetPlaceHolderText(const QString& aPlaceHolderText)
{
    mLineEdit->setPlaceholderText(aPlaceHolderText);
}


/*
 * 函数名：clear
 * 函数说明:清除
 *
 *
 * 输入参数：无
 * 输出参数：无
 * 返回值：无
 * */
void MultiSelectComboBox::clear()
{
    mListWidget->clear();
    QListWidgetItem* curItem = new QListWidgetItem(mListWidget);
    mSearchBar = new QLineEdit(this);
    mSearchBar->setPlaceholderText("Search..");
    mSearchBar->setClearButtonEnabled(true);
    mListWidget->addItem(curItem);
    mListWidget->setItemWidget(curItem, mSearchBar);

    connect(mSearchBar, &QLineEdit::textChanged, this, &MultiSelectComboBox::onSearch);
}


/*
 * 函数名：wheelEvent
 * 函数说明:鼠标的滚轮事件屏蔽，以免产生一些意外异常
 *
 *
 * 输入参数：无
 * 输出参数：无
 * 返回值：无
 * */
void MultiSelectComboBox::wheelEvent(QWheelEvent* aWheelEvent)
{
    // Do not handle the wheel event
    Q_UNUSED(aWheelEvent);
}


/*
 * 函数名：eventFilter
 * 函数说明:重写eventFilter 单独处理lineedit的鼠标点击事件
 *
 *
 * 输入参数：aObject：事件对象指针 aEvent：事件指针
 * 输出参数：无
 * 返回值：无
 * */
bool MultiSelectComboBox::eventFilter(QObject* aObject, QEvent* aEvent)
{
    if(aObject == mLineEdit && aEvent->type() == QEvent::MouseButtonRelease) {
        showPopup();
        return false;
    }
    return false;
}


/*
 * 函数名：keyPressEvent
 * 函数说明:屏蔽按键事件
 *
 *
 * 输入参数：无
 * 输出参数：无
 * 返回值：无
 * */
void MultiSelectComboBox::keyPressEvent(QKeyEvent* aEvent)
{
    // Do not handle key event
    Q_UNUSED(aEvent);
}


/*
 * 函数名：setCurrentText
 * 函数说明:设置当前文本
 *
 *
 * 输入参数：aText：QString
 * 输出参数：无
 * 返回值：无
 * */
void MultiSelectComboBox::setCurrentText(const QString& aText)
{
    Q_UNUSED(aText);
}


/*
 * 函数名：setCurrentText
 * 函数说明:设置当前文本
 *
 *
 * 输入参数：aText：list
 * 输出参数：无
 * 返回值：无
 * */
void MultiSelectComboBox::setCurrentText(const QStringList& aText)
{
    int count = mListWidget->count();

    for (int i = 1; i < count; ++i)
    {
        QWidget* widget = mListWidget->itemWidget(mListWidget->item(i));
        QCheckBox* checkBox = static_cast<QCheckBox*>(widget);
        QString checkBoxString = checkBox->text();
        if(aText.contains(checkBoxString))
        {
            checkBox->setChecked(true);
        }
    }
}


/*
 * 函数名：ResetSelection
 * 函数说明:重设选中
 *
 *
 * 输入参数：无
 * 输出参数：无
 * 返回值：无
 * */
void MultiSelectComboBox::ResetSelection()
{
    int count = mListWidget->count();

    for (int i = 1; i < count; ++i)
    {
        QWidget *widget = mListWidget->itemWidget(mListWidget->item(i));
        QCheckBox *checkBox = static_cast<QCheckBox *>(widget);
        checkBox->setChecked(false);
    }
}
